Skip to content

iceoryx2 请求响应模式:流式响应与连接生命周期 ​

请求响应是仅次于发布订阅的常用通信模型,但传统实现里「一问一答」的模式拿到机器人控制场景常常不够用:客户端请求导航到某个位置,服务端需要一路持续回报当前位置,直到到达或受阻。iceoryx2 的请求响应模式在传统语义上加了响应流——服务器可以连续发送响应,任何一方可随时终止流。本文以官方示例(App 控制 Larry 机器人自动导航)为线索,介绍 C++ 客户端与服务器的完整实现,以及连接生命周期管理的几个关键细节。

模型语义 ​

  • 一个请求对应一串响应,服务器按需持续发送;
  • 任何一方都可以终止流:客户端销毁 pending_response 对象即通知服务器停止发送;
  • 连接状态可查询,双方都能检测对端退出并及时清理资源。

客户端实现 ​

cpp
#include "iceoryx2.hpp"
using namespace iox2;

// 1. 创建节点
auto node = NodeBuilder().create<ServiceType::Ipc>().value();

// 2. 创建服务并指定请求/响应数据类型
auto service = node.service_builder(ServiceName::create("autopilot").value())
               .request_response<Position, State>()
               .open_or_create()
               .value();

// 3. 创建客户端端口
auto client = service.client_builder().create().value();

// 4. 发送请求
auto request = client.loan_uninit().value();                 // 借出未初始化的请求内存
auto initialized_request = request.write_payload(Position{{123.456F, 789.1F}});
auto pending_response = send(std::move(initialized_request)).value();

// 5. 事件循环处理响应
while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
    while (true) {
        auto position = pending_response.receive().value();  // 接收响应数据
        if (position.has_value()) {
            show_larry_position_in_app(position.value());    // 显示当前位置
        } else {
            break;  // 本轮无更多数据
        }

        // 检查连接状态
        if (!pending_response.is_connected()) {
            if (is_at_destination(position)) {
                show_larry_arrived_popup_in_app();       // 到达目的地
            } else {
                show_larry_encountered_obstacle_in_app(); // 中途受阻
            }
        }
    }
}

几个关键点:

  • send 返回的 pending_response 对象管理整个响应流的生命周期——它存活期间流就保持打开,销毁即取消;
  • receive() 返回空值表示本轮数据取完,不是流结束;流是否结束看 is_connected();
  • 断开时根据最后一个响应判断是到达目的地还是遇到障碍。

服务器实现 ​

cpp
auto node = NodeBuilder().create<ServiceType::Ipc>().value();
auto service = node.service_builder(ServiceName::create("autopilot").value())
               .request_response<Position, State>()
               .open_or_create()
               .value();
auto server = service.server_builder().create().value();

// 接收请求,active_request 管理该请求的响应流
auto active_request = server.receive().value();

while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
    // 检查是否有新请求
    if ( !active_request.has_value() ) {
        active_request = server.receive().value();
        if ( active_request.has_value() ) {
            drive_to_position(active_request);      // 开始向目标位置行驶
        }
    }

    // 处理活动请求
    if ( active_request.has_value() ) {
        if ( !active_request->is_connected() ) {    // 客户端断开连接
            stop_driving();
            active_request.reset();                 // 清空活动请求
        } else if ( arrived_at_destination() ) {    // 到达目的地
            active_request.reset();
        } else {                                    // 正常行驶中,发送状态更新
            auto response = active_request->loan_uninit().value();
            auto initialized_response = response.write_payload(get_current_state());
            send(std::move(initialized_response)).value();
        }
    }
}

服务器侧的生命周期管理:

  • 客户端断开:active_request->is_connected() 为假时停止行驶并 reset() 清空,释放该请求的资源;
  • 任务完成:到达目的地后同样 reset(),等待下一个请求;
  • 正常处理:每个周期借出响应内存、写入当前状态、发送。

关键机制 ​

  1. 双工流通信:请求发出后连接保持打开,服务器可以持续推送状态更新,客户端不需要反复发起新请求;
  2. RAII 管理资源:pending_response 与 active_request 分别在两端管理流的生命周期,对象销毁即通知对端;
  3. 非阻塞轮询:配合 node.wait 的周期循环,不阻塞线程,可与其他通信模式在同一节点共存;
  4. 双向断连检测:连接断开时双方都能通过 is_connected() 感知并清理。

这套模式适合需要持续状态反馈的控制场景:机器人导航、远程监控、长任务的进度推送。

要点 ​

  • iceoryx2 的请求响应是流式的:一个请求,一串响应,双方都可终止
  • pending_response(客户端)和 active_request(服务器)是流的两端句柄,销毁即断流
  • receive() 空值只表示本轮取完,流结束以 is_connected() 为准
  • 客户端取消流 = 销毁 pending_response,服务器会收到断连并自行停止
最近更新

基于 VitePress 构建